Статистика по интересам

  • вероятности инсталла по интересам
  • вероятности инсталла по интересам и приложениям (на выборке большего размера за сутки)
In [1]:
import pandas as pd
from os import listdir
from os.path import isfile, join
from io import StringIO

interests

ClickHouse https://redash.trg.corp.mail.ru/queries/28482/source

In [2]:
interests_path = '/home/eka.volkova/TRG-91593_interests_statistics/interests_statistics/interests_all_targeting_id.csv' # все target_id
# interests_path = '/home/eka.volkova/TRG-90187_age_means/interests.csv' # target_id = 5
# Беру интересы со всеми target_id, если брать только target_id=5, то почти 74% интересов не заполнено

interests = pd.read_csv(interests_path)
In [3]:
interests.rename(columns={'value': 'interests', 'description': 'interest_name'}, inplace=True)
interests['interests'] = interests['interests'].astype('str')
interests.set_index('interests', inplace=True)
In [4]:
interests.info()
<class 'pandas.core.frame.DataFrame'>
Index: 719 entries, 7354 to 10015
Data columns (total 1 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   interest_name  719 non-null    object
dtypes: object(1)
memory usage: 11.2+ KB
In [5]:
interests.head()
Out[5]:
interest_name
interests
7354 Авто / Автовладельцы
7358 Мобильные устройства / Сотовые телефоны и гарн...
7359 Мобильные устройства / Планшеты и электронные ...
7360 Мобильные устройства / Ноутбуки и нетбуки
7361 Одежда, обувь и аксессуары / Женская одежда

show_installs за 1 день

In [6]:
orig_data_path = '/home/eka.volkova/TRG-90187_age_means/orig_data/show_install/'
In [7]:
csv_files = [f for f in listdir(orig_data_path) if (isfile(join(orig_data_path, f)) and f.find('.csv') != -1)]
csv_files.sort()
In [8]:
csv_files
Out[8]:
['show_install_20221107002350.csv',
 'show_install_20221107022320.csv',
 'show_install_20221107041600.csv',
 'show_install_20221107062340.csv',
 'show_install_20221107082340.csv',
 'show_install_20221107102248.csv',
 'show_install_20221107122410.csv',
 'show_install_20221107142450.csv',
 'show_install_20221107162310.csv',
 'show_install_20221107182117.csv',
 'show_install_20221107202430.csv',
 'show_install_20221107222240.csv',
 'show_install_20221108002400.csv',
 'show_install_20221108022420.csv',
 'show_install_20221108041910.csv',
 'show_install_20221108062400.csv',
 'show_install_20221108082440.csv',
 'show_install_20221108101855.csv',
 'show_install_20221108122930.csv',
 'show_install_20221108142320.csv',
 'show_install_20221108162250.csv',
 'show_install_20221108182400.csv',
 'show_install_20221108202240.csv',
 'show_install_20221108222410.csv',
 'show_install_20221109002450.csv',
 'show_install_20221109022530.csv',
 'show_install_20221109042030.csv',
 'show_install_20221109062350.csv',
 'show_install_20221109082440.csv',
 'show_install_20221109102100.csv',
 'show_install_20221109122400.csv',
 'show_install_20221109142320.csv',
 'show_install_20221109162410.csv',
 'show_install_20221109182340.csv',
 'show_install_20221109202150.csv',
 'show_install_20221109222400.csv',
 'show_install_20221110002300.csv',
 'show_install_20221110022310.csv',
 'show_install_20221110041720.csv',
 'show_install_20221110062400.csv',
 'show_install_20221110082300.csv',
 'show_install_20221110102130.csv',
 'show_install_20221110122420.csv',
 'show_install_20221110142410.csv',
 'show_install_20221110162250.csv',
 'show_install_20221110182157.csv',
 'show_install_20221110202510.csv',
 'show_install_20221110222010.csv',
 'show_install_20221111002330.csv',
 'show_install_20221111022240.csv',
 'show_install_20221111042400.csv',
 'show_install_20221111062230.csv',
 'show_install_20221111082130.csv',
 'show_install_20221111102220.csv',
 'show_install_20221111122410.csv',
 'show_install_20221111142300.csv',
 'show_install_20221111162400.csv',
 'show_install_20221111182240.csv',
 'show_install_20221111202200.csv',
 'show_install_20221111222350.csv',
 'show_install_20221112002350.csv',
 'show_install_20221112022400.csv',
 'show_install_20221112042000.csv',
 'show_install_20221112062500.csv',
 'show_install_20221112082250.csv',
 'show_install_20221112101920.csv',
 'show_install_20221112122520.csv',
 'show_install_20221112142520.csv',
 'show_install_20221112162150.csv',
 'show_install_20221112182310.csv',
 'show_install_20221112202230.csv',
 'show_install_20221112222310.csv',
 'show_install_20221113002410.csv',
 'show_install_20221113022520.csv',
 'show_install_20221113041630.csv',
 'show_install_20221113062410.csv',
 'show_install_20221113082430.csv',
 'show_install_20221113101950.csv',
 'show_install_20221113122320.csv',
 'show_install_20221113142220.csv',
 'show_install_20221113162340.csv',
 'show_install_20221113182110.csv',
 'show_install_20221113202100.csv',
 'show_install_20221113221850.csv',
 'show_install_20221114002400.csv',
 'show_install_20221114022350.csv',
 'show_install_20221114041840.csv',
 'show_install_20221114062420.csv',
 'show_install_20221114082308.csv',
 'show_install_20221114102207.csv',
 'show_install_20221114122310.csv',
 'show_install_20221114142350.csv',
 'show_install_20221114162340.csv',
 'show_install_20221114182020.csv',
 'show_install_20221114202400.csv',
 'show_install_20221114222310.csv',
 'show_install_20221115002520.csv',
 'show_install_20221115022140.csv',
 'show_install_20221115042030.csv',
 'show_install_20221115062450.csv',
 'show_install_20221115082320.csv',
 'show_install_20221115102140.csv',
 'show_install_20221115122340.csv',
 'show_install_20221115142330.csv',
 'show_install_20221115162220.csv',
 'show_install_20221115182250.csv',
 'show_install_20221115202230.csv',
 'show_install_20221115222330.csv',
 'show_install_20221116002410.csv',
 'show_install_20221116022430.csv',
 'show_install_20221116041610.csv',
 'show_install_20221116061950.csv',
 'show_install_20221116082240.csv',
 'show_install_20221116101850.csv',
 'show_install_20221116122330.csv',
 'show_install_20221116142440.csv',
 'show_install_20221116162340.csv',
 'show_install_20221116182330.csv',
 'show_install_20221116202340.csv',
 'show_install_20221116222330.csv']
In [9]:
len(csv_files)
Out[9]:
120
In [10]:
len([file for file in csv_files if file[19:21] in ('07')])
Out[10]:
12

Читаем файлы в DataFrame

In [11]:
# show_install_20221107*.csv
show_install = \
pd.concat([pd.read_csv(f'{orig_data_path}{file}', sep=';') for file in [file for file in csv_files if file[19:21] in ('07')]], ignore_index=True) 
In [12]:
show_install.shape
Out[12]:
(159005975, 11)
In [13]:
show_install.replace(to_replace={'ev_type': 7}, value=1, inplace=True)
show_install['ev_type'].value_counts()
Out[13]:
0    152731803
1      6274172
Name: ev_type, dtype: int64
In [14]:
show_install['ev_type'].value_counts().sum()
Out[14]:
159005975
In [15]:
show_install.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 159005975 entries, 0 to 159005974
Data columns (total 11 columns):
 #   Column            Dtype  
---  ------            -----  
 0   age               float64
 1   age_targetings    int64  
 2   app               int64  
 3   ev_type           int64  
 4   has_interest      int64  
 5   iab_app_category  object 
 6   interests         int64  
 7   matched_bits      int64  
 8   rb_mobile_app_id  int64  
 9   sex               int64  
 10  timestamp         int64  
dtypes: float64(1), int64(9), object(1)
memory usage: 13.0+ GB

Добавляем расшифровку interests

In [16]:
show_install['interests'] = show_install['interests'].astype('str')
show_install = show_install.join(interests['interest_name'], on='interests')
show_install.fillna(value={'interest_name': 'Не определено'}, inplace=True)
show_install['interest_name'].value_counts()
Out[16]:
CrossFire: Неактивные                         3447333
Armored Warfare: Неактивные                   3447333
Armored Warfare: Незарегистрированные         3447333
CrossFire: Незарегистрированные               3447333
Skyforge: Незарегистрированные                3447333
                                               ...   
Бизнес / Юридическая поддержка                    124
Пользователи сервисов такси                       111
Образование / Средне-специальное                   79
Образование / Высшее                               79
Финансы / Игра на бирже / Бинарные опционы          2
Name: interest_name, Length: 489, dtype: int64
In [17]:
show_install[show_install['interest_name'].isna()].shape[0]
Out[17]:
0
In [22]:
show_install.head()
Out[22]:
age age_targetings app ev_type has_interest iab_app_category interests matched_bits rb_mobile_app_id sex timestamp interest_name
0 57.0 60 2825035 0 0 473 10248 0 2825035 2 1667769830 Нет высшего образования
1 57.0 60 2825035 0 0 473 12279 0 2825035 2 1667769830 ArcheAge: Незарегистрированные
2 57.0 60 2825035 0 0 473 12280 0 2825035 2 1667769830 Armored Warfare: Незарегистрированные
3 57.0 60 2825035 0 0 473 12281 0 2825035 2 1667769830 CrossFire: Незарегистрированные
4 57.0 60 2825035 0 0 473 12287 0 2825035 2 1667769830 Skyforge: Незарегистрированные

Вероятность инсталла по интересам

In [19]:
show_install_interests = show_install.copy()[['interest_name', 'ev_type']]
show_install_interests = show_install_interests.groupby(by='interest_name')['ev_type'].mean().rename('cr')
show_install_interests.sort_values(ascending=False, inplace=True)
show_install_interests.head()
Out[19]:
interest_name
Профессиональная область / Безопасность                    0.062160
Финансы / Потребительские кредиты                          0.059974
Финансы / Кредитные карты                                  0.059866
Финансы / Микрозаймы                                       0.059858
Отдел, подразделение / Обеспечение безопасности, охрана    0.059325
Name: cr, dtype: float64

Добавляем график Toп интересов

In [25]:
# import plotly.express as px
import plotly.graph_objects as go
In [26]:
top = 30
df_bar = show_install_interests.head(top).sort_values().reset_index()

fig = \
go.Figure(
    data=go.Bar(
        x=df_bar['cr'], y=df_bar['interest_name'], 
        orientation='h'),
    layout=go.Layout(
        title='Топ интересов', 
        xaxis={'domain': [0.45, 1]}, 
        yaxis={'anchor': 'free', 'position': 0, 'side': 'right'}, 
        height=20*top)
)

fig.show()

Top интересов по приложениям

Находим топ приложений по CR и определяем топ интересов для них

CR по приложениям

In [27]:
show_install_app = show_install.copy()[['interest_name', 'ev_type', 'app']]

# Количество инсталлов по приложениям должно быть хотя бы от 5 и показов от 100 
show_install_app = \
show_install_app.groupby(by='app').agg(
    shows=pd.NamedAgg(column='ev_type', aggfunc='count'), 
    installs=pd.NamedAgg(column='ev_type', aggfunc='sum'), 
    cr=pd.NamedAgg(column='ev_type', aggfunc='mean')
).query('shows + installs >= 100 and installs >= 5')

show_install_app.sort_values(by=['cr', 'installs'], ascending=[False, False], inplace=True)
In [28]:
show_install_app.head()
Out[28]:
shows installs cr
app
10409400 529 529 1.0
10380882 458 458 1.0
10387842 324 324 1.0
10406911 315 315 1.0
5138847 290 290 1.0

CR по приложениям и интересам

In [29]:
show_install_app_interest = show_install.copy()[['interest_name', 'ev_type', 'app']]

show_install_app_interest = \
show_install_app_interest.groupby(by=['app', 'interest_name']).agg(
    shows=pd.NamedAgg(column='ev_type', aggfunc='count'), 
    installs=pd.NamedAgg(column='ev_type', aggfunc='sum'), 
    cr=pd.NamedAgg(column='ev_type', aggfunc='mean')
)
show_install_app_interest.reset_index(level='interest_name', inplace=True)
show_install_app_interest.sort_values(by='cr', ascending=False, inplace=True)
In [30]:
show_install_app_interest.head()
Out[30]:
interest_name shows installs cr
app
9773251 Досуг и развлечение / Знакомства 1 1 1.0
10334664 Средний 2 2 1.0
4884033 Телезрители 1 1 1.0
10334664 Холост 2 2 1.0
4884033 Холост 1 1 1.0

Объединяем рейтинг приложений с рейтингом интересов внутри приложения

In [31]:
# Выбираем Топ N приложений по CR 
top_show_install_app = 100 # количество приложений
show_install_top_app_interest = show_install_app.head(top_show_install_app)

# Отбираем по уровню CR
# show_install_top_app_interest = show_install_app[show_install_app['cr'] == 1]

# Топ приложений с НЕ 100% CR
# show_install_top_app_interest = show_install_app[show_install_app['cr'] != 1].head(top_show_install_app)
In [32]:
show_install_top_app_interest = \
show_install_top_app_interest.iloc[:, :-4].\
join(show_install_app_interest, on='app').query('cr > 0.0')
show_install_top_app_interest.reset_index(inplace=True)
In [33]:
show_install_top_app_interest.head()
Out[33]:
app interest_name shows installs cr
0 10409400 CrossFire: Неактивные 11 11 1.0
1 10409400 Armored Warfare: Незарегистрированные 11 11 1.0
2 10409400 Armored Warfare: Неактивные 11 11 1.0
3 10409400 ArcheAge: Незарегистрированные 11 11 1.0
4 10409400 CrossFire: Незарегистрированные 11 11 1.0
In [34]:
top_interest=15 # Количество интересов в рамках одного приложения
show_install_top_app_interest = show_install_top_app_interest.groupby(by='app').head(top_interest)
In [35]:
show_install_top_app_interest.head()
Out[35]:
app interest_name shows installs cr
0 10409400 CrossFire: Неактивные 11 11 1.0
1 10409400 Armored Warfare: Незарегистрированные 11 11 1.0
2 10409400 Armored Warfare: Неактивные 11 11 1.0
3 10409400 ArcheAge: Незарегистрированные 11 11 1.0
4 10409400 CrossFire: Незарегистрированные 11 11 1.0
In [36]:
show_install_top_app_interest.shape
Out[36]:
(1500, 5)

Добавляем расшифровку app

Получаем список приложений, которые есть в обучающей выборке и выгружаем их из ClichHouse https://redash.trg.corp.mail.ru/queries/28422/source

In [37]:
app_path = '/home/eka.volkova/TRG-91593_interests_statistics/interests_statistics/app.csv'
app = pd.read_csv(app_path)

app.rename(columns={'rb_mobile_app_id': 'app', 'title': 'app_name'}, inplace=True)
app.set_index('app', inplace=True)
app.head()
Out[37]:
app_name category
app
10399771 Честно деньги: на карту быстро Финансы
1514710 Авиабилеты, отели и РЖД билеты Путешествия
9978066 Кредо займы онлайн Финансы
9721050 Робот Займер - Займы онлайн Финансы
14407 Едадил: скидки в магазинах Покупки
In [39]:
show_install_top_app_interest = show_install_top_app_interest.join(app, on='app')
In [40]:
show_install_top_app_interest.head()
Out[40]:
app interest_name shows installs cr app_name category
0 10409400 CrossFire: Неактивные 11 11 1.0 BiBi Такси Автомобили и транспорт
1 10409400 Armored Warfare: Незарегистрированные 11 11 1.0 BiBi Такси Автомобили и транспорт
2 10409400 Armored Warfare: Неактивные 11 11 1.0 BiBi Такси Автомобили и транспорт
3 10409400 ArcheAge: Незарегистрированные 11 11 1.0 BiBi Такси Автомобили и транспорт
4 10409400 CrossFire: Незарегистрированные 11 11 1.0 BiBi Такси Автомобили и транспорт

Добавляем график по интересам и приложениям

In [41]:
import plotly.graph_objects as go
import plotly.express as px
In [301]:
df_scatter = show_install_top_app_interest.copy()
# Выделяем жирным шрифтом интересы, которые были в общем Топе
df_scatter['interest_name'] = df_scatter.apply(lambda row: '<b>' + row['interest_name'] + '</b>' if (row['app'] in df_bar['interest_name']) else row['interest_name'], axis=1)
In [302]:
df_scatter.head()
Out[302]:
app interest_name shows installs cr app_name category
0 10409400 CrossFire: Неактивные 11 11 1.0 BiBi Такси Автомобили и транспорт
1 10409400 Armored Warfare: Незарегистрированные 11 11 1.0 BiBi Такси Автомобили и транспорт
2 10409400 Armored Warfare: Неактивные 11 11 1.0 BiBi Такси Автомобили и транспорт
3 10409400 ArcheAge: Незарегистрированные 11 11 1.0 BiBi Такси Автомобили и транспорт
4 10409400 CrossFire: Незарегистрированные 11 11 1.0 BiBi Такси Автомобили и транспорт
In [303]:
fig = px.scatter(
    df_scatter, x="app_name", y="interest_name", 
    color="app_name",size='cr', height = 20*show_install_top_app_interest['interest_name'].nunique(), 
    title='Рейтинг интересов по приложениям')
fig.show()